/**
 * @file   Driver.java
 * @author Enrique Madrid <e.madrid@lpcsite.com>
 * @date   Tue Oct  2 13:11:54 2007
 * 
 * @brief  
 * 
 * 
 */

package sim.framework;

import java.util.*;

/**
 * 
 * 
 */
public final class Driver extends Thread {

    private static final int QUEUE_INIT_SIZE = 4;

    private static final int LOCKED_FOR_APPEND = 1;    
    private static final int LOCKED_FOR_ATTEND = 2;    
    private static final int LOCKED_FOR_REMOVE = 3;    
    private static final int LOCKED_FOR_DELETE = 4;    
    
    private Simlet m_Simlet = null;
    private boolean m_Stop = false;
    
    // Eventos.
    private Vector m_Pending = new Vector(QUEUE_INIT_SIZE);
    private Vector m_Recycle = new Vector(QUEUE_INIT_SIZE);
    
    public Driver(Simlet s) {
	m_Simlet = s;
    }

    private Msg newMsg(final Msg m) {
        Msg msg = null;
        if (m_Recycle.size() > 0) {
            msg = (Msg)m_Recycle.firstElement();
            m_Recycle.removeElement(msg);
        }
	else {
	    msg = new Msg(m);
	}
        return msg;
    }
    private synchronized Msg lock(int lockFor, Msg m) {
	Msg msg = null;
	switch(lockFor) {
	case Driver.LOCKED_FOR_APPEND:
	    msg = lockedForAppend(m);
	    break;
	case Driver.LOCKED_FOR_REMOVE:
	    msg = lockedForRemove();
	    break;
	case Driver.LOCKED_FOR_DELETE:
	    lockedForDelete(m);
	    break;
	}
	return msg;
    }

    private Msg lockedForAppend(Msg m) {
        Msg msg = null;
	// Crear nuevo mensaje
	msg = newMsg(m);
	// Añadirlo a las lista de tareas pendientes.
	m_Pending.addElement(msg);	
	// Notificar a la hebra.
	notify();
	return msg;
    }

    private void lockedForDelete(Msg msg) {
	// Añadir el mensaje para reciclarlo en otras tareas.
	m_Recycle.addElement(msg);
    }

    private Msg lockedForRemove() {
	Msg msg = null;
	
	if (m_Pending.size() > 0) {
	    msg = (Msg)m_Pending.firstElement();
	    m_Pending.removeElement(msg);
	}
	
	return msg;
    }

    public void run() {
        Msg msg;   

	while (!m_Stop) {

	    msg = remove();
	    while(msg != null) {
		m_Simlet.event(msg);
		delete(msg);
		msg = remove();
	    }

	    synchronized (this) { 
		try {
		    wait(0);
		} catch( InterruptedException e ) {
		    
		};
	    }
	}
    }

    protected synchronized void stop() {
        m_Stop = true;
        notify();
    }

    protected boolean postEvent(final Msg msg) {
	return (lock(LOCKED_FOR_APPEND, msg) != null);
    }

    private Msg remove() {
	return lock(LOCKED_FOR_REMOVE, null);
    }

    private void delete(Msg msg) {
	lock(LOCKED_FOR_DELETE, msg);
    }
}
